import { PageComponent, html, NE, renderMaps } from 'nvagir'
import axios from 'axios'

import './PlayGround.less'
import { bindAutoRemove, debounce, isVisible } from '../../utils'
import MainSideBar from '../../components/MainSideBar/MainSideBar'

let loading = false

// 图片url数组
const imgUrl = [
  'https://img2.baidu.com/it/u=1728522718,1340994382&fm=26&fmt=auto&gp=0.jpg',
  'https://img0.baidu.com/it/u=1783627040,2442271822&fm=26&fmt=auto&gp=0.jpg',
  'https://img0.baidu.com/it/u=880523998,3904595583&fm=26&fmt=auto&gp=0.jpg',
]

/** render data type */
type Item = {
  title: string
  description: string
}

/**
 * Get page data list
 * @param page get page number
 * @return promise with data list
 */
const getList = (() => {
  const preObj = {} as { cancel: () => void; p: Promise<Item[]> }

  return (page: number) => {
    loading = true

    preObj.cancel?.()
    const p = new Promise<Item[]>(rs => {
      preObj.cancel = () => {
        console.log('canceled')
        rs([] as Item[])
      }
    })
    return Promise.race([
      axios
        .get<{ list: Item[] }>(
          'https://www.fastmock.site/mock/a6fba8390908eb19fcd04a85555171a0/test/demo',
          { params: { page } },
        )
        .then(res => {
          console.log(res.data.list)
          return res.data.list
        })
        .catch(err => {
          console.log(err)
          return [] as Item[]
        })
        .finally(() => (loading = false)),
      p,
    ])
  }
})()

/**
 * Get single column width
 * @param num several columns
 * @param nodeWidth target width
 * @return get target left and right margin
 */
function getSingleMargin(num: number, nodeWidth: number): number {
  let width = document.documentElement.clientWidth || document.body.clientWidth
  let contentWidth = num * nodeWidth
  let marginGap = width - contentWidth
  let singleMargin = marginGap / (num * 2)
  return singleMargin
}

const WaterfallItem = (item: Item, onLoad: () => void) => {
  const { el } = html<{
    img: HTMLImageElement
  }>`
    <li class="item">
      <div class="item__img">
        <img n@load=${onLoad} src="${imgUrl[0]}" />
      </div>
      <h4 class="item__title">${item.title}</h4>
      <p class="item__info">${item.description}</p>
    </li>
  `
  // doms.img.src = imgUrl[0]
  // doms.img.onload = onLoad
  const component: NE<'waterfallItem'> = {
    name: 'waterfallItem',
    el,
  }
  return component
}

const PlayGround: PageComponent = () => {
  const data = {
    list: [] as [Item, () => void][],
  }
  let singleMargin: number,
    pageNo = 1,
    colHeight: number[] = []
  async function dataProcess(isFirst = false) {
    if (loading) return
    const list = await getList(pageNo)
    pageNo++
    list.forEach(item => {
      const onload = () => {
        if (isFirst) {
          waterFall(dom, isFirst)
          isFirst = false
        } else {
          waterFall(dom)
        }
      }
      const {
        el: { dom },
      } = WaterfallItem(item, onload)

      data.list.push([item, onload])
      doms.list.appendChild(dom)
    })
  }

  const waterFall = (dom: HTMLElement, isFirst: boolean = false) => {
    let nodeWidth = dom.offsetWidth,
      nodeHeight = dom.clientHeight
    if (isFirst) {
      // 首次调用的时候
      let colNum = Math.floor(doms.page.offsetWidth / nodeWidth)
      singleMargin = getSingleMargin(colNum, nodeWidth)
      for (let i = 0; i < colNum; i++) {
        colHeight[i] = 0
      }
    }
    let index = 0,
      minSumHeight = colHeight[0]

    for (var i = 0; i < colHeight.length; i++) {
      if (colHeight[i] < minSumHeight) {
        index = i
        minSumHeight = colHeight[i]
      }
    }

    dom.style.left = (nodeWidth + singleMargin * 2) * index + 'px'
    dom.style.top = minSumHeight + 'px'
    dom.style.opacity = '1'
    colHeight[index] = nodeHeight + colHeight[index] + 10
    doms.list.style.height = Math.max(...colHeight) + 'px'
  }

  function reStart() {
    pageNo = 1
    renderMaps(doms.list, WaterfallItem, components, ...data.list)
    loading = false
    dataProcess(true)
  }

  const bindEvent = () => {
    bindAutoRemove('/playGround', 'scroll', () => {
      if (!isVisible(doms.load)) {
        return
      }
      dataProcess()
    })
    bindAutoRemove('/playGround', 'resize', debounce(reStart, 1000))
  }
  const { el, doms, components } = html<
    {
      page: HTMLElement
      list: HTMLElement
      load: HTMLElement
    },
    [typeof WaterfallItem[]]
  >`
    <div n@name="page" class="index-page">
      <ul n@name="list" class="waterfall-list"></ul>
      <div n@name="load" style="color: white;">-</div>
      ${MainSideBar()}
    </div>
  `

  dataProcess(true)
  bindEvent()
  return { el }
}

export default PlayGround
